package main

import (
	"archive/zip"
	"fmt"
	时间类 "gitee.com/go_888/extends/carbon"
	扩展类 "gitee.com/go_888/extends/extend"
	压缩类 "gitee.com/go_888/extends/goframe/gcompress"
	转换类 "gitee.com/go_888/extends/goframe/gconv"
	文件类 "gitee.com/go_888/extends/goframe/gfile"
	加密md5类 "gitee.com/go_888/extends/goframe/gmd5"
	文本类 "gitee.com/go_888/extends/goframe/gstr"
	ini类 "gitee.com/go_888/extends/ini"

	"io"
	"os"
	"path"
	"path/filepath"
)

var ini *ini类.X配置项
var 原始目录 string
var 目标目录 string
var 忽略文件配置 []string
var 忽略文件 []string
var 是否终止 bool
var err error

func main() {
	配置文件路径 := 文件类.X路径生成(文件类.X取当前工作目录(), 文件类.X取文件名且不含扩展名(文件类.X取当前进程名())+".ini")
	ini, err = ini类.X创建(配置文件路径)
	if err != nil || 文件类.X是否存在文件(配置文件路径) == false {
		ini, _ = ini类.X创建并从文本(`
[配置]
原始目录=
目标目录=
;忽略更新=*.log|*.lsp|*.zip|*.rar|*侧边栏.ini|*.bak
`)
		ini.X保存(配置文件路径)
		fmt.Println("读取配置文件失败," + err.Error())
		fmt.Println("已创建配置文件,请修改配置文件后重新运行")
		扩展类.X延时(5000)
		return
	}
	原始目录 = 文本类.X删首尾空与字符(ini.X取文本值("配置", "原始目录"), 文件类.X常量_文件_系统分隔符)
	目标目录 = 文本类.X删首尾空与字符(ini.X取文本值("配置", "目标目录"), 文件类.X常量_文件_系统分隔符)
	忽略文件配置 = ini.X取文本数组("配置", "忽略更新", "|")
	忽略文件配置 = append(忽略文件配置, "*\\"+文件类.X取当前进程名())
	忽略文件配置 = append(忽略文件配置, 文件类.X路径生成(文件类.X取当前工作目录(), "*\\"+文件类.X取文件名且不含扩展名(文件类.X取当前进程名())+".ini"))

	已处理数量 := 0
	已忽略数量 := 0
	if 原始目录 == "" {
		fmt.Println("原始目录不能为空")
		扩展类.X延时(5000)
		return
	}
	if 目标目录 == "" {
		fmt.Println("目标目录不能为空")
		扩展类.X延时(5000)
		return
	}
	更新列表 := []string{}
	文件列表 := []string{}
	文件类.X枚举文件_函数(原始目录, "*", true, func(路径 string) string {
		文件名, err := 加密md5类.X加密(文件类.X读字节集(路径))
		相对路径 := 文本类.X取右边(路径, 原始目录)
		相对路径 = 文本类.X替换(相对路径, 文件类.X常量_文件_系统分隔符, "\\")
		新路径 := 文件类.X路径生成(目标目录, 文件名+".gz")
		文件列表 = append(文件列表, 相对路径)

		路径是否忽略 := false
		for i := range 忽略文件配置 {
			路径是否忽略, _ = path.Match(忽略文件配置[i], 路径)
			if 路径是否忽略 == true {
				已忽略数量 += 1
				fmt.Println("已跳过:" + 相对路径)
				忽略文件 = append(忽略文件, 相对路径)
				break
			}
		}

		if 路径是否忽略 == false && 是否终止 == false {
			已处理数量 += 1
			if err != nil {
				fmt.Println("失败! 获取文件md5:" + err.Error())
				是否终止 = true
				return ""
			}

			文件类.X删除(新路径)
			err = 压缩类.Gzip压缩文件(路径, 新路径)
			if err != nil {
				fmt.Println("失败! 错误:" + err.Error())
				是否终止 = true
				return ""
			}

			更新列表 = append(更新列表, 相对路径+"||"+文件名+".gz")
			fmt.Println("已处理:" + 相对路径)
			return ""
		}

		return ""
	})

	文件类.X删除(文件类.X路径生成(目标目录, "_完整安装包.zip"))
	err = zipFiles(原始目录, 文件类.X路径生成(目标目录, "_完整安装包.zip"))
	if err != nil {
		fmt.Println("压缩失败! _完整安装包.zip :" + err.Error())
		是否终止 = true
	} else {
		文件类.X写入文本(文件类.X路径生成(目标目录, "_更新列表.txt"), 文本类.X连接(更新列表, "\n"))
		文件类.X写入文本(文件类.X路径生成(目标目录, "_文件列表.txt"), 文本类.X连接(文件列表, "\n"))
		文件类.X写入文本(文件类.X路径生成(目标目录, "_更新说明.txt"), "")
		年, 月, 日 := 时间类.X创建并按当前时间().X设置时区(时间类.X常量_时区_中国).X取年月日()
		文件类.X写入文本(文件类.X路径生成(目标目录, "_更新日期.txt"), 转换类.X取文本(年)+"-"+转换类.X取文本(月)+"-"+转换类.X取文本(日))
	}
	fmt.Println("已结束,已处理数量:" + 转换类.X取文本(已处理数量) + ", 已忽略数量:" + 转换类.X取文本(已忽略数量))

	if len(忽略文件) > 0 {
		fmt.Println("以下为忽略文件:")
		for i := range 忽略文件 {
			fmt.Println(忽略文件[i])
		}
	}

	扩展类.X延时(5000)
}

// zipFiles 压缩指定目录下的文件到 ZIP 文件，不含主目录
func zipFiles(sourceDir, zipPath string) error {
	// 创建 ZIP 文件
	zipFile, err := os.Create(zipPath)
	if err != nil {
		return err
	}
	defer zipFile.Close()

	// 创建 zip.Writer
	writer := zip.NewWriter(zipFile)
	defer writer.Close()

	// 遍历源目录
	return filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 跳过目录
		if info.IsDir() {
			return nil
		}

		// 打开文件
		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()

		// 获取相对路径，去掉主目录
		relPath, err := filepath.Rel(sourceDir, path)
		if err != nil {
			return err
		}

		// 创建 ZIP 文件中的条目
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		header.Name = relPath
		header.Method = zip.Deflate

		// 创建 ZIP 文件中的写入器
		writerFile, err := writer.CreateHeader(header)
		if err != nil {
			return err
		}

		// 将文件内容复制到 ZIP 文件中
		_, err = io.Copy(writerFile, file)
		return err
	})
}
